#ifndef __W25QXX_H
#define __W25QXX_H

#include "stm32f10x.h"

/* W25Q64JV Flash芯片命令定义 */
#define W25X_WriteEnable        0x06    // 写使能命令
#define W25X_WriteDisable       0x04    // 写禁止命令
#define W25X_ReadStatusReg      0x05    // 读状态寄存器命令
#define W25X_WriteStatusReg     0x01    // 写状态寄存器命令
#define W25X_ReadData          0x03     // 读数据命令
#define W25X_FastReadData       0x0B    // 快速读取数据命令
#define W25X_PageProgram        0x02    // 页编程命令
#define W25X_BlockErase         0xD8    // 块擦除命令(64KB)
#define W25X_SectorErase        0x20    // 扇区擦除命令(4KB)
#define W25X_ChipErase         0xC7     // 芯片擦除命令
#define W25X_PowerDown         0xB9     // 进入掉电模式命令
#define W25X_ReleasePowerDown   0xAB    // 退出掉电模式命令
#define W25X_DeviceID          0xAB     // 读取设备ID命令
#define W25X_ManufactDeviceID   0x90    // 读取制造商/设备ID命令
#define W25X_JedecDeviceID      0x9F    // 读取JEDEC ID命令

/* 函数声明 */
/**
 * @brief 初始化W25QXX Flash
 * @note 初始化SPI接口和CS引脚
 */
void W25QXX_Init(void);

/**
 * @brief 读取W25QXX的ID
 * @return uint16_t ID值(高8位为制造商ID,低8位为设备ID)
 * @note W25Q64JV的制造商ID为0xEF,设备ID为0x16
 */
uint16_t W25QXX_ReadID(void);

/**
 * @brief 从指定地址读取指定长度的数据
 * @param pBuffer 数据存储缓冲区指针
 * @param ReadAddr 读取的起始地址(24bit)
 * @param NumByteToRead 要读取的字节数
 */
void W25QXX_Read(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead);

/**
 * @brief 在指定地址写入一页数据
 * @param pBuffer 数据存储缓冲区指针
 * @param WriteAddr 写入的起始地址(24bit)
 * @param NumByteToWrite 要写入的字节数(最大256,即一页)
 * @note 必须确保所写的地址范围内的数据全部为0xFF,否则在非0xFF处写入的数据将失败
 */
void W25QXX_Write_Page(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite);

/**
 * @brief 无检验写入数据
 * @param pBuffer 数据存储缓冲区指针
 * @param WriteAddr 写入的起始地址(24bit)
 * @param NumByteToWrite 要写入的字节数
 * @note 必须确保所写的地址范围内的数据全部为0xFF,否则在非0xFF处写入的数据将失败
 */
void W25QXX_Write_NoCheck(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite);

/**
 * @brief 写入数据(在写入前会自动擦除扇区)
 * @param pBuffer 数据存储缓冲区指针
 * @param WriteAddr 写入的起始地址(24bit)
 * @param NumByteToWrite 要写入的字节数
 */
void W25QXX_Write(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite);

/**
 * @brief 擦除一个扇区
 * @param Dst_Addr 扇区地址,根据实际容量设置
 * @note 擦除一个扇区的最少时间:150ms
 */
void W25QXX_Erase_Sector(uint32_t Dst_Addr);

/**
 * @brief 擦除整个芯片
 * @note 等待时间超长...
 */
void W25QXX_Erase_Chip(void);

#endif 